Hi 大家,經過前兩天的環境建置和 Cargo 工具學習,今天我們將要開始深入 Rust 語言的核心——變數和資料型別。這些是所有程式語言的基礎,但 Rust 有其獨特的設計理念,特別是在記憶體安全和效能方面的考量。
在 Rust 中,使用 let
關鍵字來宣告變數:
fn main() {
let x = 5;
println!("x 的值是: {}", x);
}
Rust 中的變數預設是不可變的(immutable),這是 Rust 安全性設計的重要特色:
fn main() {
let x = 5;
println!("x 的值是: {}", x);
// 這行會產生編譯錯誤!
// x = 6; // 錯誤:cannot assign twice to immutable variable
}
如果需要修改變數的值,必須使用 mut
關鍵字:
fn main() {
let mut x = 5;
println!("x 的值是: {}", x);
x = 6; // 現在可以修改了
println!("x 的新值是: {}", x);
}
Rust 允許用同樣的名字宣告新變數,這稱為「遮蔽」:
fn main() {
let x = 5;
let x = x + 1; // 遮蔽前一個 x
let x = x * 2; // 再次遮蔽
println!("x 的值是: {}", x); // 輸出: 12
// 甚至可以改變型別
let spaces = " ";
let spaces = spaces.len(); // 從字串變成數字
println!("空格數量: {}", spaces);
}
Rust 提供多種整數型別,分為有號和無號:
fn main() {
// 有號整數(可以是負數)
let signed_8: i8 = -128; // -128 到 127
let signed_16: i16 = -32768; // -32,768 到 32,767
let signed_32: i32 = -2000; // 預設整數型別
let signed_64: i64 = -4000; // 64 位元
let signed_128: i128 = -8000; // 128 位元
let signed_size: isize = -100; // 依系統架構決定
// 無號整數(只能是正數或零)
let unsigned_8: u8 = 255; // 0 到 255
let unsigned_16: u16 = 65535; // 0 到 65,535
let unsigned_32: u32 = 4000; // 0 到 4,294,967,295
let unsigned_64: u64 = 8000; // 更大範圍
let unsigned_128: u128 = 16000; // 最大範圍
let unsigned_size: usize = 100; // 依系統架構決定
println!("signed_32: {}, unsigned_32: {}", signed_32, unsigned_32);
}
fn main() {
let decimal = 98_222; // 十進位,可用底線分隔
let hex = 0xff; // 十六進位
let octal = 0o77; // 八進位
let binary = 0b1111_0000; // 二進位
let byte = b'A'; // 位元組(僅限 u8)
println!("十進位: {}, 十六進位: {}, 八進位: {}", decimal, hex, octal);
println!("二進位: {}, 位元組: {}", binary, byte);
}
fn main() {
let f1 = 2.0; // f64(預設)
let f2: f32 = 3.0; // f32(單精度)
println!("f64: {}, f32: {}", f1, f2);
// 數學運算
let sum = f1 + f2 as f64; // 需要型別轉換
println!("總和: {}", sum);
}
fn main() {
let is_true = true;
let is_false: bool = false;
println!("真: {}, 假: {}", is_true, is_false);
// 布林運算
let result = is_true && !is_false;
println!("運算結果: {}", result);
}
fn main() {
let c = 'z';
let z = 'ℤ';
let heart_eyed_cat = '😻';
let chinese_char = '中';
println!("字元: {}, {}, {}, {}", c, z, heart_eyed_cat, chinese_char);
// 字元是 4 位元組的 Unicode
println!("字元大小: {} 位元組", std::mem::size_of::<char>());
}
元組可以將多個不同型別的值組合成一個複合型別:
fn main() {
let tup: (i32, f64, u8) = (500, 6.4, 1);
// 解構賦值
let (x, y, z) = tup;
println!("x: {}, y: {}, z: {}", x, y, z);
// 使用索引存取
let first = tup.0;
let second = tup.1;
let third = tup.2;
println!("第一個: {}, 第二個: {}, 第三個: {}", first, second, third);
// 空元組(單位型別)
let unit = ();
println!("單位型別: {:?}", unit);
}
陣列中的所有元素必須是相同型別,且長度固定:
fn main() {
// 基本陣列宣告
let a = [1, 2, 3, 4, 5];
let months = ["一月", "二月", "三月", "四月", "五月", "六月"];
// 指定型別和長度
let b: [i32; 5] = [1, 2, 3, 4, 5];
// 初始化相同值的陣列
let c = [3; 5]; // 相當於 [3, 3, 3, 3, 3]
println!("第一個陣列: {:?}", a);
println!("月份陣列: {:?}", months);
println!("相同值陣列: {:?}", c);
// 存取陣列元素
let first = a[0];
let second = a[1];
println!("第一個元素: {}, 第二個元素: {}", first, second);
// 陣列長度
println!("陣列長度: {}", a.len());
}
fn main() {
// 型別推斷
let guess = "42".parse().expect("不是數字!"); // 錯誤:型別不明確
// 正確的方式 - 明確指定型別
let guess: u32 = "42".parse().expect("不是數字!");
println!("猜測的數字: {}", guess);
// 或使用 turbofish 語法
let guess2 = "42".parse::<u32>().expect("不是數字!");
println!("另一個猜測: {}", guess2);
}
const MAX_POINTS: u32 = 100_000;
const PI: f64 = 3.14159265359;
fn main() {
println!("最高分數: {}", MAX_POINTS);
println!("圓周率: {}", PI);
}
static HELLO_WORLD: &str = "Hello, world!";
static mut COUNTER: usize = 0;
fn main() {
println!("{}", HELLO_WORLD);
// 修改靜態可變變數需要 unsafe 區塊
unsafe {
COUNTER += 1;
println!("計數器: {}", COUNTER);
}
}
我們來建立一個實用的程式來練習今天學到的概念:
use std::io;
fn main() {
println!("=== 資料型別轉換工具 ===");
loop {
println!("\n請選擇轉換類型:");
println!("1. 攝氏轉華氏");
println!("2. 華氏轉攝氏");
println!("3. 公里轉英里");
println!("4. 英里轉公里");
println!("5. 離開");
let mut input = String::new();
io::stdin().read_line(&mut input).expect("讀取失敗");
let choice: u32 = match input.trim().parse() {
Ok(num) => num,
Err(_) => {
println!("請輸入有效數字!");
continue;
}
};
match choice {
1 => celsius_to_fahrenheit(),
2 => fahrenheit_to_celsius(),
3 => km_to_miles(),
4 => miles_to_km(),
5 => {
println!("感謝使用!");
break;
}
_ => println!("無效選項,請重新選擇!"),
}
}
}
fn celsius_to_fahrenheit() {
println!("請輸入攝氏溫度:");
let celsius = read_f64();
let fahrenheit = celsius * 9.0 / 5.0 + 32.0;
println!("{}°C = {:.2}°F", celsius, fahrenheit);
}
fn fahrenheit_to_celsius() {
println!("請輸入華氏溫度:");
let fahrenheit = read_f64();
let celsius = (fahrenheit - 32.0) * 5.0 / 9.0;
println!("{}°F = {:.2}°C", fahrenheit, celsius);
}
fn km_to_miles() {
println!("請輸入公里數:");
let km = read_f64();
let miles = km * 0.621371;
println!("{} 公里 = {:.2} 英里", km, miles);
}
fn miles_to_km() {
println!("請輸入英里數:");
let miles = read_f64();
let km = miles * 1.60934;
println!("{} 英里 = {:.2} 公里", miles, km);
}
fn read_f64() -> f64 {
loop {
let mut input = String::new();
io::stdin().read_line(&mut input).expect("讀取失敗");
match input.trim().parse::<f64>() {
Ok(num) => return num,
Err(_) => println!("請輸入有效數字!"),
}
}
}
今天我們學習了 Rust 中變數和基本資料型別的核心概念。重點包括:
mut
關鍵字才能修改明天我們將介紹函式的定義和使用 ~